
//  JavaScript 词法和语法的代码分析
// 利用正则文法 表示产生式

let xregexp = { // 正则表达式里，() 能分组也能捕获 只想分组不想捕获，需要加上?:
  InputElement: "<Whitespace>|<LineTerminator>|<Comments>|<Token>",
  Whitespace: / /,
  LineTerminator: /\n/,
  Comments: /\/\*([^*]|\*[^\/])*\*\/|\/\/[^\n]*/,
  Token: "<Literal>|<Keywords>|<Identifer>|<Punctuator>",
  Literal: "<NumbericLiteral>|<BooleanLiteral>|<StringLiteral>|<NullLiteral>",
  NumbericLiteral: /(?:[1-9][0-9]*|0)(?:\.[0-9]*)?|\.[0-9]+/,
  BooleanLiteral: /true|false/,
  StringLiteral: /\"(?:[^"\n]|\\[\s\S])*\"|\'(?:[^'\n]|\\[\s\S])*\'/,
  NullLiteral: /null/,
  Keywords: /if|else|for|function|let|var/,
  Identifer: /[a-zA-Z_$][a-zA-Z0-9_$]*/,
  Punctuator: /\+|\,|\?|\.|\:|\{|\}|\(|\)|\[|\]|\=|\<|\>|\+\+|\=\=|\=\>|\*|;/
}

class XRegExp { // 封装一个类(词法分析器) 重写exec、lastIndex 重新进行编译，并分成有序列的部分
  constructor(source, flag, root = 'root') {
    this.table = new Map() // 使用 Map 类型进行构造
    this.regexp = new RegExp(this.compileRegExp(source, root, 0).source, flag)
    // console.log(this.regexp)
    // console.log(this.table)
  }

  compileRegExp(source, name, start) { // start 序号
    if (source[name] instanceof RegExp) // 区分叶子节点
      return {
        source: source[name].source,
        length: 0
      }
    
    let length = 0
    
    // 匹配每个尖括号里面的内容 要算在对应的数组里的位置，需要知道length 
    let regexp = source[name].replace(/\<([^>]+)\>/g, (str, $1) => {
      this.table.set(start + length, $1)

      ++length

      let r = this.compileRegExp(source, $1, start + length)

      length += r.length

      return "(" + r.source + ")"
    })

    return {
      source: regexp,
      length
    }
  }

  exec(string) {
    let r = this.regexp.exec(string)
    // console.log.log(r)
    for(let i = 1; i < r.length; i++) { // 循环匹配对应的值 从1开始
      if (r[i] !== void 0) {
        // console.log(this.table.get(i - 1))
        r[this.table.get(i - 1)] = r[i]
      }
    }
    return r
  }

  get lastIndex() {
    return this.regexp.lastIndex
  }

  set lastIndex(newVal) {
    return this.regexp.lastIndex = newVal
  }
}

export function* scan(str) {
  // let regexp = / |\n|\/\*([^*]|\*[^\/])*\*\/|\/\/[^\n]*|[1-9][0-9]*|0/g
  // let regexp = new RegExp(compileRegExp(xregexp, "InputElement"), "g")
  let regexp = new XRegExp(xregexp, "g", "InputElement")

  while(regexp.lastIndex < str.length) {
    let r = regexp.exec(str)
    // console.log(r)
    // document.write(r[0])

    if(r.Whitespace) { // 用yield 包成symbol 做区分match 出来的多个表达式

    } else if(r.LineTerminator) {

    } else if(r.Comments) {

    } else if(r.NumbericLiteral) {
      yield {
        type: 'NumbericLiteral',
        value: r[0]
      }

    } else if(r.BooleanLiteral) {
      yield {
        type: 'BooleanLiteral',
        value: r[0]
      }

    } else if(r.StringLiteral) {
      yield {
        type: 'StringLiteral',
        value: r[0]
      }

    } else if(r.NullLiteral) {
      yield {
        type: 'NullLiteral',
        value: null
      }

    } else if(r.Identifer) { // 已经没有值了
      yield {
        type: 'Identifer',
        name: r[0]
      }

    } else if(r.Keywords) {
      yield {
        type: r[0]  // 就是本身自己
      }

    } else if(r.Punctuator) {
      yield {
        type: r[0]
      }

    } else {
      throw new Error('unexpected token ' + r[0])
    }

    if (!r[0].length) break;
  }

  yield { // 返回一个结束标记
    type: 'EOF'
  }

}




// let source = (`
// for(let i = 0; i < 3; i++) {
//   for(let j = 0; j < 3; j++) {
//     let cell = document.createElement("div");
//     cell.classList.add("cell");
//     cell.innerText = pattern[i * 3 + j] == 2 ? "❌" :
//       pattern[i * 3 + j] == 1 ? "⭕" : "";
//     cell.addEventListener("click", () => userMove(j, i));
//     board.appendChild(cell);
//   }
//   board.appendChild(document.createElement("br"));
// }
// `)

// for(let element of scan(source)) {
//   console.log(element)
// }
